package {
	
	import flash.display.*;
	import flash.events.*;
	import flash.geom.Point;
	import flash.system.*;
	import flash.text.*;
	import flash.ui.Keyboard;
	import flash.utils.*;
	
	import org.papervision3d.cameras.*;
	import org.papervision3d.core.geom.Lines3D;
	import org.papervision3d.core.geom.renderables.Line3D;
	import org.papervision3d.core.geom.renderables.Vertex3D;
	import org.papervision3d.core.layers.RenderLayer;
	import org.papervision3d.core.render.data.RenderHitData;
	import org.papervision3d.events.InteractiveScene3DEvent;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.*;
	import org.papervision3d.materials.shaders.GouraudShader;
	import org.papervision3d.materials.shaders.ShadedMaterial;
	import org.papervision3d.materials.special.LineMaterial;
	import org.papervision3d.objects.primitives.*;
	import org.papervision3d.render.*;
	import org.papervision3d.scenes.*;
	import org.papervision3d.view.*;
	
	[SWF(frameRate="31", width="800", height="800", backgroundColor="0x3D403E")]
	public class Drag3D extends Sprite{
		
		private var viewport:Viewport3D;
		private var renderer:BasicRenderEngine = new BasicRenderEngine();
		private var scene:Scene3D = new Scene3D();
		private var camera:Camera3D = new Camera3D();

		public var dragPlane:Plane = new Plane(new ColorMaterial(0x00FF00, 0), 1500,1500, 6, 6);
		
		[Embed(source="meshes/bamboo.jpg")]
		public var bamboo:Class;
		
		public var sphere:Sphere;
		
		private var angC:Number= 0;
		private var ang:Number=0;
		private var by:Number = 0;
		private var autoRotate:Boolean = false;
		private var gravity:Boolean = false;
		private var locked:Boolean = false;
		
		public var isDragging = false;
		
		private var vx:Number = 0;
		private var vy:Number = 0;
		private var vz:Number = 0;
		
		private var ox:Number;
		private var oy:Number;
		private var oz:Number;
		
		
	
		
		public function Drag3D():void {
			
			stage.align = StageAlign.TOP_LEFT;
			stage.quality = StageQuality.MEDIUM;
			
			
			var tFormat:TextFormat = new TextFormat("Arial");
			tFormat.color = 0xFFFFFF;
			tFormat.bold = true;
			
			var tF:TextField = new TextField();
			tF.multiline = true;
			tF.width = 400;
			tF.height = 500;
			tF.selectable = false;
			tF.htmlText = "Controls:<br>'A': Toggle xz/xy dragging<br>'S' : Toggle 'slanted' dragging<br>'L': Toggle relative/world drag mode<br>'V': Toggle 'dragplane' visibility<br>'G' : Toggle Physics<br>'R' : Toggle auto rotate<br>arrow keys: rotate";
			tF.setTextFormat(tFormat);
			addChild(tF);
			tF.x = 10;
			tF.y = 10;
			
			
			
			viewport = new Viewport3D(800, 800, false, true);
						
			addChild(viewport);

			
			var light:PointLight3D = new PointLight3D();
			light.x = -1000;
			light.z = 1000;
			light.y = 1000;
			var gour:GouraudShader = new GouraudShader(light, 0xFFFFFF, 0x404040);
			var bm:BitmapMaterial = new BitmapMaterial(Bitmap(new bamboo()).bitmapData);
			var shadeMat:ShadedMaterial = new ShadedMaterial(bm, gour);
			
			
			sphere = new Sphere(shadeMat, 100);
			
			scene.addChild(sphere);
			scene.addChild(dragPlane);
			camera.zoom = 11;
			camera.x = 1000;
			camera.z = 1000;
			camera.y = 100;
			
			sphere.material.interactive = true;
			
			dragPlane.material.interactive = true;
			dragPlane.rotationX = -90;
			
			var dP:RenderLayer = new RenderLayer();
			viewport.addRenderLayer(dP);
			
			dP.alpha = 0.2;
			
			dragPlane.renderLayer = dP;
			dragPlane.material.doubleSided = true;

					
			drawGrid();
			
			sphere.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS, handlePress);
			addEventListener(Event.ENTER_FRAME, enterFrameFunction);
			addEventListener(MouseEvent.MOUSE_UP, handleRelease);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, handleKDown);
			stage.addEventListener(KeyboardEvent.KEY_UP, handleKUp);
			
		}
		
		public function handlePress(e:InteractiveScene3DEvent){
		
	
			isDragging  = true;
			sphere.material.interactive = false;
			dragPlane.material.interactive = true;
			
			 dragPlane.copyPosition(sphere);
		}
		
		public function handleKDown(e:KeyboardEvent){
		
			if(e.keyCode == Keyboard.LEFT)
				angC += 0.01;
			
			if(e.keyCode == Keyboard.RIGHT)
				angC -= 0.01;
			
		}
		
		public function handleKUp(e:KeyboardEvent){
			
		
				
			if(isChar(e.charCode, "a")){
				if(dragPlane.rotationX != -90)
					dragPlane.rotationX = -90;
				else
					dragPlane.rotationX = 0;
			}
			
			if(isChar(e.charCode, "s")){
					dragPlane.rotationX = 45;
			}
			
			if(isChar(e.charCode, "v")){
				
				var cm:ColorMaterial = ColorMaterial(dragPlane.material);
				if(cm.fillAlpha == 0)
					cm.fillAlpha = 0.5;
				else
					cm.fillAlpha = 0; 
				
			}
			if(isChar(e.charCode, "r")){
				autoRotate = !autoRotate;
			}
			if(isChar(e.charCode, "l")){
				locked = !locked;
			}
			if(isChar(e.charCode, "g")){
				gravity = !gravity;
			}
			
		}
		
		private function isChar(code:Number, str:String){
			if(code == str.charCodeAt())
				return true;
			return false;
		}

		
		public function handleRelease(e:MouseEvent){
			
			isDragging  =false;
			sphere.material.interactive = true;
			dragPlane.material.interactive = false;
			
			vx = sphere.x - ox;
			vy = sphere.y - oy;
			vz = sphere.z - oz;
			
			e.updateAfterEvent();
		}
		
		public function drawGrid():void{
			
			var s:Sprite = new Sprite();
			
			s.graphics.lineStyle(1, 0x909090, 1);
			s.graphics.moveTo(0,0);
			
			var xx = 0;
			var yy = 0;
			var lm:LineMaterial = new LineMaterial(0x909090);
			var lines:Lines3D = new Lines3D(lm);
			
			var dist:Number = 80;
			
			for(var i:int = 0;i<11;i++){
				var v1:Vertex3D = new Vertex3D(i*dist,0, 0);
				var v2:Vertex3D = new Vertex3D(i*dist,0,10*dist);
				var l:Line3D = new Line3D(lines, lm, 1, v1, v2);
				lines.addLine(l);
				
			}
			
			for(var i:int = 0;i<11;i++){
				var v1:Vertex3D = new Vertex3D(0,0, i*dist);
				var v2:Vertex3D = new Vertex3D(10*dist,0,i*dist);
				var l:Line3D = new Line3D(lines, lm, 1, v1, v2);
				lines.addLine(l);
				
			}

			scene.addChild(lines);
			
			lines.x = -400;
			lines.z = -400;
			
		}
		
		
		private function enterFrameFunction(e:Event):void{

			ox = sphere.x;
			oy = sphere.y;
			oz = sphere.z;
			
			 dragPlane.copyPosition(sphere);

			if(isDragging){
				
				var rh:RenderHitData = viewport.hitTestPoint2D(new Point(viewport.containerSprite.mouseX, viewport.containerSprite.mouseY));
				
				if(rh.hasHit){

					sphere.x = rh.x
					sphere.y = rh.y;
					sphere.z = rh.z;
					
					vx = vy = vz = 0;
					
					
					by = sphere.y;
					ang = 0;
				}

				
			}			
			
			if(locked){
				var ang:Number = Math.atan2(camera.z, camera.x)*180/Math.PI-90;
				dragPlane.rotationY = -ang;
			}
			
			
			if(gravity){
				
				vx *= 0.85;
				vy *= 0.9;
				vz *= 0.85;
				
				sphere.x += vx;
				sphere.y += vy;
				sphere.z += vz;
				
				vy -= 4;
				
				if(sphere.y < 0)
					vy += 3.8+(Math.abs(sphere.y)/100*1.8);	
			}

			
			camera.x = Math.sin(angC)*1200;
			camera.z = Math.cos(angC)*1200;
			camera.y = 500;
			
			if(autoRotate)
				angC += 0.01;
			
			
			render();
			
			

		}
		
		private function render():void {
			renderer.renderScene(scene, camera, viewport);
		}
				
		
	}
}
